package com.feiya.pianoscore;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.Manifest;

import com.feiya.pianoscore.ScoreView.FM_ClefValue;
import com.feiya.pianoscore.ScoreView.FM_Const;
import com.feiya.pianoscore.ScoreView.FM_DurationValue;
import com.feiya.pianoscore.ScoreView.FM_Note;
import com.feiya.pianoscore.ScoreView.FM_ScorePlayer;

public class MainActivity extends AppCompatActivity/* implements View.OnClickListener*/ {
    final static String TAG = Constants.TAG;
    public boolean      isRecording = false;
    int MY_PERMISSION_REQUEST_CODE = 11;
    Button recordButton;
    Button stopRecordButton;
    Button switchButton;
    Button playButton;
    Button stopPlayButton;
    TextView freqText;
    ScoreViewController scoreViewController;
    boolean recordMode = true;
    private MediaPlayer mediaPlayer;

    long startTime;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {

            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO},
                    MY_PERMISSION_REQUEST_CODE);

        } else {
            AubioHelper.getInstance().init();
        }

        recordButton = findViewById(R.id.button_record);
        //stopRecordButton = findViewById(R.id.button_stop_record);
        switchButton = findViewById(R.id.button_switch);
        playButton = findViewById(R.id.button_play);
        stopPlayButton = findViewById(R.id.button_stop_play);
        //recordButton.setOnClickListener(this);
        //stopButton.setOnClickListener(this);
        freqText = findViewById(R.id.pitchView);
        showRecordBtn();

        scoreViewController = new ScoreViewController(this);
        scoreViewController.ShowScore(this,files[0], GlobalConfig.DEBUG_RECORDTRACK);

        updateRecordShow(recordMode);

        if(GlobalConfig.DEBUG_RECORDTRACK)
            this.freqText.setVisibility(View.VISIBLE);
        else
            this.freqText.setVisibility(View.INVISIBLE);

        /*for(int i=1;i<=88;i++){
            float freq = scoreViewController.Note2Frequency(i);

            int[] notes = scoreViewController.GetNoteWithFrequency(FM_ClefValue.TREBLE,freq);
            Log.d(TAG, i+" freq: "+freq+"  note:"+notes[0]+"  Oct:"+notes[1]+"  Acc:"+notes[2]);
        }*/
       /* for(int oct=1;oct<=7;oct++){
            LogNote2Key(0,oct, FM_Accidental.None);
            LogNote2Key(0,oct, FM_Accidental.Sharp);
            LogNote2Key(1,oct, FM_Accidental.None);
            LogNote2Key(1,oct, FM_Accidental.Sharp);
            LogNote2Key(2,oct, FM_Accidental.None);
            LogNote2Key(3,oct, FM_Accidental.None);
            LogNote2Key(3,oct, FM_Accidental.Sharp);
            LogNote2Key(4,oct, FM_Accidental.None);
            LogNote2Key(4,oct, FM_Accidental.Sharp);
            LogNote2Key(5,oct, FM_Accidental.None);
            LogNote2Key(5,oct, FM_Accidental.Sharp);
            LogNote2Key(6,oct, FM_Accidental.None);
        }*/
        long startTime = SystemClock.elapsedRealtime();
    }
    void LogNote2Key(int note,int oct,int acc){
        FM_Note n = new FM_Note(this.scoreViewController.scoreView.dynamicScore,note, oct, FM_ClefValue.TREBLE, acc, FM_DurationValue.NOTE_EIGHTH, 0, true);
        int track = scoreViewController.scoreView.GetIndex(n);
        Log.d(TAG,  "note:"+ note+ " oct:"+ oct+  " acc:"+ acc+"  key:"+ScoreViewController.GetKeyWithNote(note,oct,acc)+"  track:"+track);

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == MY_PERMISSION_REQUEST_CODE) {

            if (ContextCompat.checkSelfPermission(this,
                    Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED)
            {
                AubioHelper.getInstance().init();
            }
        }
    }

    Runnable frameRunnable;
    Handler frameHandler;
    private CountDownTimer countDownTimer;
    boolean countDownEnd;
    long lastSecond = 0;
    public void startRecord()
    {
        Log.d(TAG,"start record");

        isRecording = true;
        AubioHelper.getInstance().startRecord(this, new AubioHelper.ActionRecordRun() {
            @Override
            public void perform() {
                //onStartRecord();
            }
        });

        //倒计时处理
        countDownEnd = false;
        countDownTimer = new CountDownTimer(4000, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {
                // 在倒计时过程中执行的操作，比如更新UI
                long secondsRemaining = millisUntilFinished / 1000;
                //countdownText.setText("倒计时: " + secondsRemaining + " 秒");
                if(lastSecond != secondsRemaining){
                    lastSecond = secondsRemaining;

                    playTickSound();
                    Log.d(TAG, "on count down: "+secondsRemaining+"  cur time:"+getCurTime());
                }
            }
            @Override
            public void onFinish() {
                // 倒计时完成时执行的操作
                //countdownText.setText("倒计时结束！");
                countDownEnd = true;
                mediaPlayer.release();
                mediaPlayer = null;
                scoreViewController.Play(!GlobalConfig.DEBUG_PLAYMUSIC, new FM_ScorePlayer.OnPlayEnd() {
                    @Override
                    public void Callback() {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                DoStopRecord();
                            }
                        });
                    }
                });
            }
        };
        // 启动倒计时
        countDownTimer.start();

        //每帧执行
        frameHandler = new Handler();
        frameRunnable = new Runnable() {
            @Override
            public void run() {
                // 在这里执行每帧的操作
                float frequency = AubioHelper.getInstance().getPitch();
                if(GlobalConfig.DEBUG_RECORDTRACK)
                    freqText.setText(String.valueOf(frequency));

                freqQueue.add(frequency);
                if(freqQueue.size() > queueSaveFrame)
                    freqQueue.remove(0);

                if(frequency > 0){
                    //Log.d(TAG, "run: frequency:"+frequency);
                }

                 if(countDownEnd) {

                    for (int i=0;i<freqQueue.size();i++){

                        if(i <= queueSaveFrame - noteNeedFreqStayFrame){
                            float ele = freqQueue.get(i);
                            if(ele > 0){
                                int goodCount = 1;
                                for (int j=i+1;j<freqQueue.size();j++){
                                    boolean fit = Math.abs(freqQueue.get(j) - ele) < 12;
                                    if(fit)
                                        goodCount++;
                                    if(goodCount >= noteNeedFreqStayFrame)
                                        break;
                                }
                                if(goodCount >= noteNeedFreqStayFrame){
                                    int midinote = scoreViewController.Frequency2Note(ele);
                                    if(midinote != lastDetectNote) {
                                        int[]notes=ScoreViewController.GetNoteWithFrequency(FM_ClefValue.TREBLE,frequency);
                                        lastDetectNote = midinote;
                                        Log.d(TAG, "检测到音符频率:" + frequency + " 由音高:"+midinote+  " 计算得note:" + notes[0]+" oct:"+notes[1]+" acc:"+notes[2]);
                                        scoreViewController.AddRecordNote(frequency);
                                    }
                                    break;
                                }
                            }
                        }
                    }

                    m_lastFrequency = frequency;
                }

                // 通过 handler.postDelayed 实现每帧调用
                frameHandler.postDelayed(this, 16); // 16 毫秒表示大约 60 帧每秒
            }
        };
        frameHandler.post(frameRunnable);
    }
    List<Float> freqQueue = new ArrayList<>();
    int queueSaveFrame = 7;
    int lastDetectNote;
    int logIndex;
    int freqStayFrameCount;
    int noteNeedFreqStayFrame = 4;
    int continueNotFitFrame;
    float m_lastFrequency;
    float checkFrequency;
    boolean frequencyUp;

    void playTickSound(){
        playSound("sounds/tick.wav");
    }

    void playSound(String fileName){
        if(mediaPlayer == null)
            mediaPlayer = new MediaPlayer();
        else
            mediaPlayer.reset();
        try {
            AssetFileDescriptor assetFileDescriptor = getAssets().openFd(fileName);
            // 设置MediaPlayer的数据源为AssetFileDescriptor
            mediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(),
                    assetFileDescriptor.getStartOffset(), assetFileDescriptor.getLength());
            mediaPlayer.prepare(); // 准备播放
            mediaPlayer.start(); // 开始播放
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    void TestAddNote(){
       /* float[] rands = new float[20];
        for(int i=0;i< rands.length;i++)
        {
            Random random = new Random();
            // 生成一个随机整数
            float randomNumber = random.nextInt(900);
            rands[i] = randomNumber;
        }
        scoreViewController.AddNotes(rands);*/
    }

    public void stopRecord()
    {
        Log.d(TAG,"stop record");
        isRecording = false;
        AubioHelper.getInstance().stopRecord();
        frameHandler.removeCallbacks(frameRunnable);
        scoreViewController.Stop();
    }

    float m_LastClickStopRecordTime;
    public void OnClickRecord(View v){
        if(!isRecording)
        {
            if (ContextCompat.checkSelfPermission(this,
                    Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED)
            {
                isRecording = true;

                startRecord();

                showStopBtn();
            }
            else
            {
                Log.e(TAG,"no permission!");
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO},
                        MY_PERMISSION_REQUEST_CODE);
            }
        }
        else {
            DoStopRecord();

            m_LastClickStopRecordTime = getCurTime();
            Log.d(TAG, "OnClickStartRecord: stop record  time:"+m_LastClickStopRecordTime);
        }
    }

    float getCurTime() {
        long elapsedTime = SystemClock.elapsedRealtime() - startTime;
        return (float)(elapsedTime / 1000);
    }

    void DoStopRecord(){
        if(isRecording) {
            stopRecord();
            showRecordBtn();
        }
    }

    public void OnClickSwitch(View v){
        if(getCurTime() - m_LastClickStopRecordTime < 1)
            return;

        recordMode = !recordMode;
        updateRecordShow(recordMode);
        this.scoreViewController.updateShowRecordTrack(this, GlobalConfig.DEBUG_RECORDTRACK);
    }
    void updateRecordShow(boolean showRecord){
        if(showRecord) {
            showRecordBtn();
            this.switchButton.setText("切到音乐");
            this.recordButton.setVisibility(View.VISIBLE);
            this.playButton.setVisibility(View.INVISIBLE);
            this.stopPlayButton.setVisibility(View.INVISIBLE);
        }
        else{
            this.switchButton.setText("切到录制");
            this.recordButton.setVisibility(View.INVISIBLE);
            //this.stopRecordButton.setVisibility(View.INVISIBLE);
            this.playButton.setVisibility(View.VISIBLE);
            this.stopPlayButton.setVisibility(View.VISIBLE);
        }
    }
    public void OnClickPlay(View v){
        Log.d(TAG, "OnClickPlay!");
        this.scoreViewController.Play(false,null);
    }
    public void OnClickStop(View v){
        Log.d(TAG, "OnClickStop!");
        this.scoreViewController.Stop();
    }

    String[] files = {"test.json", "furelise.json"};
    int index;
    public void OnClickChange(View v){
        if(getCurTime() - m_LastClickStopRecordTime < 1)
            return;

        if(isRecording)
            stopRecord();
        index++;
        index %= files.length;
        this.scoreViewController.ShowScore(this,files[index], GlobalConfig.DEBUG_RECORDTRACK);
    }
    public void OnClickBBox(){
        this.scoreViewController.OnClickBBox();
    }

    void showRecordBtn(){
        //Log.d(TAG, "showRecordBtn!");
        this.recordButton.setBackgroundResource(R.drawable.button_record);
    }
    void showStopBtn(){
        //Log.d(TAG, "showStopBtn!");
        this.recordButton.setBackgroundResource(R.drawable.button_stop);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mediaPlayer != null) {
            mediaPlayer.release();
        }
    }
}